0100 ; +-------------------+ 0105 ; | MUSIC SYNTHESIZER | 0110 ; | by Ken Collier | 0115 ; +-------------------+ 0120 ; 0125 ; Page Six variables. 0130 ; 0135 *= $0600 0140 ; 0145 SYNCNT *= *+4 syn counter 0150 VIBCNT *= *+4 vibrato counter 0155 ATTACK *= *+4 attack counter 0160 DECAY *= *+4 decay counter 0165 DROP *= *+4 minimum volume 0170 VRANGE *= *+4 vibrato range 0175 VSPEED *= *+4 vibrato speed 0180 VCOUNT *= *+4 voice counter 0185 LINECNT *= *+4 line counter 0190 TRANSPOS *= *+4 transpose value 0195 HIGHVOL *= *+4 maximum volume 0200 GETNOTE *= *+4 need new note 0205 DURCNT *= *+4 duration count 0210 PATTACK *= *+10 phrase attack 0215 PDECAY *= *+10 phrase decay 0220 PDROP *= *+10 phrase min vol 0225 PVRANG *= *+10 phrase v.range 0230 PVSPEED *= *+10 phrase v.speed 0235 NMBUF *= *+4 numeric buffer 0240 ; 0245 ; Page Zero variables. 0250 ; 0255 *= $80 0260 ; 0265 TABLE *= *+28 voices/phrases 0270 TIED *= *+4 tied note flags 0275 PTR *= *+2 temp index 0280 PINDX *= *+2 print index 0285 P2NDX *= *+2 print index 2 0290 TMP2 *= *+2 temporary 2 0295 XSTORE *= *+1 voice index 0300 VOLNOW *= *+4 current volume 0305 NOTE *= *+1 note value 0310 ACCID *= *+1 accidental 0315 TMP *= *+1 temporary 0320 PTRL *= *+4 phrase addr low 0325 PTRH *= *+4 phrase addr hi 0330 REPEAT *= *+1 repeat music 0335 STATUS *= *+4 voice status 0340 VSTAT *= *+4 vibrato status 0345 TEMPO *= *+1 music speed 0350 VNOTE *= *+4 vibrato sound 0355 SYNSTAT *= *+4 syn status 0360 ; 0365 FR0 = $D4 F.P. register 0 0370 CIX = $F2 F.P. index 0375 INBUFF = $F3 F.P. buffer 0380 ; 0385 ; Miscellaneous labels. 0390 ; 0395 CIOV = $E456 CIO vector 0400 SIOINV = $E465 SIO init vector 0405 AFP = $D800 ASCII to F.P. 0410 FASC = $D8E6 F.P. to ASCII 0415 IFP = $D9AA INTEGER to F.P. 0420 FPI = $D9D2 F.P. to INTEGER 0425 ICCOM = $0342 command byte 0430 ICBAL = $0344 buffer addr lo 0435 ICBAH = $0345 buffer addr hi 0440 ICBLL = $0348 buffer len lo 0445 ICBLH = $0349 buffer len hi 0450 ICAX1 = $034A aux info 1 0455 ICAX2 = $034B aux info 2 0460 OPEN = $03 open command 0465 CLOSE = $0C close command 0470 READ = $07 get characters 0475 EOF = 136 end file flag 0480 IOCB2 = $20 IOCB #2 offset 0485 IOCB3 = $30 IOCB #3 offset 0490 WSPACE = $2A00 workspace addr 0495 BUFS = $2A00 buffer size 0500 AUDF1 = $D200 audio freq 1 0505 AUDC1 = $D201 audio volume 1 0510 SDLSTL = $0230 display list 0515 COLBK = $02C8 backgnd color 0520 BRKKEY = $11 break key flag 0525 CONSOL = $D01F console speaker 0530 SKCTL = $D20F serial I/O ctrl 0535 AUDCTL = $D208 audio control 0540 WSYNC = $D40A wait for sync 0545 RETURN = $9B return key 0550 BACKS = $7E backspace key 0555 VLEN = $40 voice buff len 0560 ; 0565 *= $2000 loads here! 0570 ; 0575 ; Setup the program. 0580 ; 0585 START CLD clear decimal 0590 JSR CLRTBL clear tables 0595 JSR SETDL set display 0600 JSR OPENKBD open keyboard 0605 JMP STOPIT continue 0610 ; 0615 ; Input MUSIC COMPOSER files. 0620 ; 0625 DATAIN LDX #IOCB3 use IOCB #3 0630 LDA #NAME&$FF filename lo 0635 STA ICBAL,X buffer addr lo 0640 LDA #NAME/256 filename hi 0645 STA ICBAH,X buffer addr hi 0650 JSR OPENIT open file 0655 BMI ERROR error? 0660 LDA #READ get characters 0665 STA ICCOM,X command byte 0670 LDA #BUFF&$FF read buffer lo 0675 STA ICBAL,X buffer addr lo 0680 LDA #BUFF/256 read buffer hi 0685 STA ICBAH,X buffer addr hi 0690 LDA #BUFS&$FF read len lo 0695 STA ICBLL,X buffer len lo 0700 LDA #BUFS/256 read len hi 0705 STA ICBLH,X buffer len hi 0710 JSR CIOV read music data 0715 CPY #EOF end of file? 0720 BNE ERROR yes. 0725 CLOSEIT LDA #CLOSE close cmd 0730 STA ICCOM,X command byte 0735 JMP CIOV close file 0740 ; 0745 ; Input/output error handler. 0750 ; 0755 ERROR STY FR0 save error code 0760 JSR BELL ring bell 0765 LDX #ETX&$FF I/O err msg lo 0770 LDY #ETX/256 I/O err msg hi 0775 JSR CURNT2 print msg+code 0780 LDX #IOCB3 use IOCB 3 0785 JSR CLOSEIT close file 0790 PLA pull two byte 0795 PLA return address 0800 JMP CHOICE choose option 0805 ; 0810 ; Read through data and find 0815 ; PHRASE data,VOICE data, and 0820 ; MISCELLANEOUS data and store 0825 ; location in table. 0830 ; 0835 POINTERS LDA #0 get zero 0840 STA PTR index lo 0845 LDY #BUFF/256 buff addr hi 0850 STY PTR+1 index hi 0855 TAY set Y to zero 0860 SET1 LDA (PTR),Y get byte 0865 CMP #170 header byte? 0870 BNE SET2 no. 0875 INY increment index 0880 BNE WHICH1 overflow? 0885 INC PTR+1 yes, inc high 0890 WHICH1 LDA (PTR),Y get byte 0895 BMI MISC misc. record? 0900 TAX use as index 0905 STY TABLE,X save address 0910 LDA PTR+1 of record in 0915 STA TABLE+1,X table 0920 JMP ENDMARK continue 0925 MISC LDA #3 offset by 3 0930 STA PTR bytes in index 0935 LDA (PTR),Y get tempo 0940 ASL A times 2 0945 ASL A times 4 0950 ASL A times 8 0955 STA TEMPO save tempo 0960 LDA #0 get zero to 0965 STA PTR reset index 0970 ENDMARK INY inc index 0975 BNE END1 overflow? 0980 INC PTR+1 yes. inc hi 0985 END1 LDA (PTR),Y get byte 0990 CMP #255 end of record? 0995 BEQ SET2 yes. 1000 INY inc index 1005 BNE ENDMARK overflow? 1010 INC PTR+1 yes. inc hi 1015 JMP ENDMARK continue 1020 SET2 INY inc index 1025 BNE SET3 overflow? 1030 INC PTR+1 yes. inc hi 1035 SET3 LDA (PTR),Y get byte 1040 CMP #255 end of file? 1045 BNE SET1 no. 1050 ; 1055 ; Transfer the VOICE records 1060 ; to storage areas set aside. 1065 ; 1070 LDX #6 set counter 1075 TR1 LDA TRVTBL,X voice addr lo 1080 STA TMP2 index lo 1085 LDA #VC1/256 voice addr hi 1090 STA TMP2+1 index hi 1095 LDA #255 end of rec flag 1100 LDY #1 record offset 1105 STA (TMP2),Y init record 1110 DEY zero Y register 1115 LDA TABLE+20,X voice rec lo 1120 STA PTR index lo 1125 LDA TABLE+21,X voice rec hi 1130 STA PTR+1 index hi 1135 BEQ TRN empty voice rec 1140 TR2 LDA (PTR),Y put voice byte 1145 STA (TMP2),Y in voice buf 1150 INY inc index 1155 LDA (PTR),Y put 2nd byte 1160 STA (TMP2),Y in voice buf 1165 INY inc index 1170 CMP #255 end of voice? 1175 BNE TR2 no. 1180 TRN DEX yes. dec count 1185 DEX index by 2 1190 BPL TR1 all voices? 1195 RTS yes. continue 1200 ; 1205 TRVTBL .WORD VC1,VC2 voice addr 1210 .WORD VC3,VC4 table 1215 ; 1220 ; Erase old table before input. 1225 ; 1230 CLRTBL LDX #27 init index 1235 LDA #0 get zero 1240 CT1 STA TABLE,X store table 1245 DEX dec index 1250 BPL CT1 done? 1255 RTS yes. continue 1260 ; 1265 ; Check to see if a VOICE 1270 ; needs a new record. 1275 ; 1280 NEEDREC LDX #3 init index 1285 LDA #6 init voice index 1290 STA XSTORE save voice index 1295 NEXTREC LDA STATUS,X active? 1300 BEQ INCX no. 1305 CMP #2 need voice rec? 1310 BNE GETREC yes. 1315 JMP PLAYIT play note 1320 ; 1325 ; Get a new VOICE record 1330 ; and process the info. 1335 ; 1340 GETREC JSR FINDREC record byte 1345 CMP #7 valid commands? 1350 BCS STATUS1 no. end voice 1355 TAY make index 1360 LDA JMPTBL,Y jmp addr lo 1365 STA TMP2 jmp pointer lo 1370 LDA JMPTBH,Y jmp addr hi 1375 STA TMP2+1 jmp pointer hi 1380 JSR FINDREC operand byte 1385 JMP (TMP2) go to it 1390 ; 1395 JMPTBL .BYTE NEXTREC&$FF,GOTO1&$FF 1400 .BYTE PLAY1&$FF,TRANS1&$FF 1405 .BYTE VOLUME1&$FF,NEXTREC&$FF 1410 .BYTE COUNT1&$FF 1415 JMPTBH .BYTE NEXTREC/256,GOTO1/256 1420 .BYTE PLAY1/256,TRANS1/256 1425 .BYTE VOLUME1/256,NEXTREC/256 1430 .BYTE COUNT1/256 1435 ; 1440 ; Clear status. 1445 ; 1450 STATUS1 LDA #0 get zero 1455 STA STATUS,X stop voice 1460 ; 1465 ; Increment to next VOICE. 1470 ; 1475 INCX DEX dec index 1480 TXA put in Acc 1485 ASL A times 2 1490 STA XSTORE voice index 1495 BPL NEXTREC done yet? 1500 RTS yes. continue 1505 ; 1510 ; Lookup next VOICE command 1515 ; in VOICE storage area. 1520 ; 1525 FINDREC INC VCOUNT,X voice cnt 1530 LDA FTBL,X voice addr lo 1535 STA PTR index lo 1540 LDA #VC1/256 voice addr hi 1545 STA PTR+1 index hi 1550 LDY VCOUNT,X voice count 1555 LDA (PTR),Y get byte 1560 RTS continue 1565 ; 1570 FTBL .BYTE VC1&$FF voice table 1575 .BYTE VC2&$FF 1580 .BYTE VC3&$FF 1585 .BYTE VC4&$FF 1590 ; 1595 ; If VOICE record is a GOTO 1600 ; then process the jump. 1605 ; 1610 GOTO1 SEC set carry 1615 SBC #1 subtract 1 1620 ASL A multiply by 2 1625 DEC LINECNT,X dec linecount 1630 BEQ NEXTREC done? yes. 1635 STA VCOUNT,X point to line 1640 JMP NEXTREC get next record 1645 ; 1650 ; Set sound parameters for 1655 ; PHRASE number and set index to 1660 ; PHRASE's location in memory. 1665 ; 1670 PLAY1 TAY use as index 1675 LDA PATTACK,Y attack shadow 1680 STA ATTACK,X attack count 1685 LDA PDECAY,Y decay shadow 1690 STA DECAY,X decay count 1695 LDA PDROP,Y min vol shadow 1700 STA DROP,X min vol value 1705 LDA PVRANG,Y f-range shadow 1710 STA VRANGE,X freq. range 1715 LDA PVSPEED,Y speed shadow 1720 STA VSPEED,X vibrato speed 1725 TYA index to Acc 1730 ASL A multiply by 2 1735 TAY to index again 1740 LDA #1 get one 1745 STA STATUS,X get rec status 1750 STA GETNOTE,X need a note 1755 LDA TABLE,Y phrase addr lo 1760 STA PTRL,X phrase tbl lo 1765 LDA TABLE+1,Y phrase addr hi 1770 STA PTRH,X phrase tbl hi 1775 BEQ PLAY2 data in table? 1780 INC STATUS,X yes. play it 1785 PLAY2 JMP NEXTREC get next rec 1790 ; 1795 ; Set volume. 1800 ; 1805 VOLUME1 ASL A times 2 1810 ORA #$A0 pure tone 1815 STA HIGHVOL,X save it 1820 JMP NEXTREC get next rec 1825 ; 1830 ; Store the PHRASE count. 1835 ; 1840 COUNT1 STA LINECNT,X save count 1845 JMP NEXTREC get next rec 1850 ; 1855 ; Do transposition. 1860 ; 1865 TRANS1 STA TRANSPOS,X transpose 1870 JMP NEXTREC get next rec 1875 ; 1880 ; Iinitialize screen. 1885 ; 1890 SETDL LDA #DLIST&$FF display lo 1895 STA SDLSTL DL pointer lo 1900 LDA #DLIST/256 display hi 1905 STA SDLSTL+1 DL pointer hi 1910 LDA #$62 dark blue 1915 STA COLBK background 1920 RTS continue 1925 ; 1930 ; Get new file. 1935 ; 1940 RETRIEVE JSR DEFAULT do defaults 1945 JSR CLRTBL clear table 1950 JSR NAMEIT get filename 1955 JSR DATAIN read data 1960 JSR POINTERS set pointers 1965 JMP NMBR1 back to menu 1970 ; 1975 ; Get user input from keyboard. 1980 ; 1985 CHOICE JSR GETKEY get character 1990 PHA push value 1995 JSR ERASE erase window 2000 PLA pull value 2005 CMP #'L play the music? 2010 BEQ LISTEN yes. 2015 CMP #'R load file? 2020 BEQ RETRIEVE yes. 2025 CMP #'N repeat count? 2030 BEQ NUMBER yes. 2035 CMP #'P phrase change? 2040 BEQ CPHRASE yes. 2045 CMP #'T tempo change? 2050 BEQ CTEMPO yes. 2055 JSR BELL ring bell 2060 JMP CHOICE try again 2065 ; 2070 ; LISTEN to the music. 2075 ; 2080 LISTEN LDA TABLE+21 OR together 2085 ORA TABLE+23 high bytes of 2090 ORA TABLE+25 voice pointers 2095 ORA TABLE+27 to see if any 2100 BNE LIS1 are active? 2105 JMP NODATA no. 2110 LIS1 LDX #QTX&$FF play msg lo 2115 LDY #QTX/256 play msg hi 2120 JSR PRINTD print msg 2125 JSR PDEFAULT set defaults 2130 PLAYING JSR NEEDREC voice rec 2135 JSR DELAY synthesizer 2140 JSR BRKCHK break key? 2145 JMP FINISHED all done? 2150 ; 2155 ; Store # times to repeat music. 2160 ; 2165 NUMBER LDX #NMTX&$FF number msg lo 2170 LDY #NMTX/256 number msg hi 2175 JSR PRINTD print msg 2180 JSR GETNUM get number 2185 BPL NMBR0 range error? 2190 NMBRE JSR RINGER yes. ring bell 2195 JMP NUMBER try again 2200 NMBR0 BNE NMBR1 return? 2205 TAX no. put in X 2210 BEQ NMBRE value zero? 2215 DEX no. 1-255 2220 STX REPEAT store 0-254 2225 NMBR1 JSR ERASE erase window 2230 JMP CHOICE goto menu 2235 ; 2240 ; Change TEMPO of playback. 2245 ; 2250 CTEMPO LDA TEMPO get tempo 2255 JSR CURRENT print it 2260 LDX #TTX&$FF tempo msg lo 2265 LDY #TTX/256 tempo msg hi 2270 JSR TXNUM ? msg / get num 2275 BPL TEM1 numeric error? 2280 TEME JSR RINGER yes. ring bell 2285 JMP CTEMPO try again 2290 TEM1 BNE NMBR1 return? 2295 TAX no. 2300 BEQ TEME zero value? 2305 STA TEMPO no. 1-255 2310 JMP NMBR1 continue 2315 ; 2320 ; Change parameters of 2325 ; sound for one phrase. 2330 ; 2335 CPHRASE LDX #PTX&$FF phrase msg lo 2340 LDY #PTX/256 phrase msg hi 2345 JSR TXNUM print/get num 2350 BNE NMBR1 return? 2355 CMP #10 no. >9? 2360 BCC C1C no. 2365 C1E JSR RINGER ring bell 2370 JMP CPHRASE try again 2375 C1C TAX test zero flag 2380 BEQ C1E num = zero? 2385 STA XSTORE no. save number 2390 ASL A times 2 2395 TAY use as index 2400 LDA TABLE+1,Y phrase addr hi 2405 BNE C3 active phrase? 2410 JMP NODATA no. 2415 C3 JSR ERASE erase window 2420 LDX XSTORE get phrase # 2425 LDA PATTACK,X attack value 2430 JSR CURRENT print it 2435 LDX #ATX&$FF attack msg lo 2440 LDY #ATX/256 attack msg hi 2445 JSR TXNUM print/get num 2450 BPL C3A numeric error? 2455 C3E JSR BELL no. ring bell 2460 JMP C3 try again 2465 C3A BNE C5A return? 2470 TAX no. test zero 2475 BEQ C3E zero value? 2480 LDX XSTORE no. get index 2485 STA PATTACK,X save attack 2490 C5A JSR ERASE erase window 2495 LDX XSTORE get index 2500 LDA PDECAY,X decay value 2505 JSR CURRENT print it 2510 LDX #DTX&$FF decay msg lo 2515 LDY #DTX/256 decay msg hi 2520 JSR TXNUM print/get num 2525 BPL C5B numeric error? 2530 C5E JSR BELL yes. ring bell 2535 JMP C5A try again 2540 C5B BNE C6A return? 2545 TAX no. test zero 2550 BEQ C5E zero? 2555 LDX XSTORE no. get index 2560 STA PDECAY,X new decay 2565 C6A JSR ERASE erase window 2570 LDX XSTORE get index 2575 LDA #$AE maximum volume 2580 SEC set carry flag 2585 SBC PDROP,X sub min volume 2590 LSR A 0..14 => 0..7 2595 JSR CURRENT print it 2600 LDX #VTX&$FF v.drop msg lo 2605 LDY #VTX/256 v.drop msg hi 2610 JSR TXNUM print/get num 2615 BMI C6E numeric error? 2620 BNE C8A no. return? 2625 CMP #8 no. >7? 2630 BCC C8C no. continue 2635 C6E JSR BELL yes. ring bell 2640 JMP C6A try again 2645 C8C ASL A multiply by 2 2650 STA TMP use later 2655 LDA #$AE maximum volume 2660 SEC set carry 2665 SBC TMP subtract drop 2670 LDX XSTORE get index 2675 STA PDROP,X minimum volume 2680 C8A JSR ERASE erase window 2685 LDX XSTORE get index 2690 LDA PVRANG,X vibrato range 2695 JSR CURRENT print it 2700 LDX #RTX&$FF v.range msg lo 2705 LDY #RTX/256 v.range msg hi 2710 JSR TXNUM print/get num 2715 BPL C8B numeric error? 2720 JSR BELL yes. ring bell 2725 JMP C8A try again 2730 C8B BNE C10A return? 2735 LDX XSTORE no. get index 2740 STA PVRANG,X vibrato range 2745 C10A JSR ERASE erase window 2750 LDX XSTORE get index 2755 LDA PVSPEED,X vibrato speed 2760 JSR CURRENT print it 2765 LDX #STX&$FF v.speed msg lo 2770 LDY #STX/256 v.speed msg hi 2775 JSR TXNUM print/get num 2780 BPL C10B numeric error? 2785 C10E JSR BELL yes. ring bell 2790 JMP C10A try again 2795 C10B BNE C11A return? 2800 TAX no. test zero 2805 BEQ C10E yes. error 2810 LDX XSTORE get index 2815 STA PVSPEED,X vibrato speed 2820 C11A JMP NMBR1 continue 2825 ; 2830 TXNUM JSR PRINTD print string 2835 JMP GETNUM get number 2840 ; 2845 ; Play the notes. 2850 ; 2855 PLAYIT LDY XSTORE get index 2860 LDA GETNOTE,X need note? 2865 BNE NEWNOTE yes. get a note 2870 DEC DURCNT,X dec note length 2875 BEQ NOTEDONE note done? yes. 2880 JMP INCX another voice 2885 NOTEDONE LDA TIED,X note tied? 2890 BNE NEWNOTE yes. skip 2895 STA AUDF1,Y poke ultrasonic 2900 STA AUDC1,Y zero volume 2905 NEWNOTE INC PTRL,X note pntr lo 2910 BNE NW2 overflow? no. 2915 INC PTRH,X note pntr hi 2920 NW2 LDA TIED,X note tied? 2925 BNE NW3A yes. skip 2930 LDA #1 attack token 2935 STA SYNSTAT,X set status 2940 LDA ATTACK,X attack count 2945 STA SYNCNT,X save count 2950 LDA #$A2 starting volume 2955 STA AUDC1,Y poke hardware 2960 STA VOLNOW,X save volume 2965 NW3A LDA #0 get zero 2970 TAY set Y to zero 2975 STA ACCID init accidental 2980 STA VSTAT,X vibrato status 2985 STA GETNOTE,X not any more 2990 LDA VSPEED,X vibrato speed 2995 STA VIBCNT,X speed count 3000 LDA PTRL,X phrase ptr lo 3005 STA PTR save pointer lo 3010 LDA PTRH,X phrase ptr hi 3015 STA PTR+1 save pointer hi 3020 LDA (PTR),Y get note 3025 CMP #85 rest? 3030 BNE NW3 no. skip 3035 TYA Acc = 0 3040 STA SYNSTAT,X synthesizer off 3045 LDY XSTORE get index 3050 STA AUDC1,Y zero volume 3055 JMP GETDURA get duration 3060 NW3 CMP #86 Cf6? 3065 BNE NW4 no. skip 3070 LDA #36 C6 index 3075 JMP NW40 get frequency 3080 NW4 CMP #127 measure? 3085 BNE NW5 no. skip 3090 INC PTRL,X note pointer lo 3095 BNE NEWNOTE overflow? no. 3100 INC PTRH,X note pointer hi 3105 JMP NEWNOTE get a new note 3110 NW5 CMP #255 end of phrase? 3115 BNE NW6 no. skip 3120 LDA #0 get a zero 3125 STA SYNSTAT,X synthesizer off 3130 LDY XSTORE get index 3135 STA AUDC1,Y zero volume 3140 LDA #1 get voice token 3145 STA STATUS,X set status 3150 JMP NEXTREC next voice rec 3155 NW6 LSR A divide by 2 3160 ROL ACCID carry into ACCID 3165 LSR A divide by 4 3170 ROL ACCID carry into ACCID 3175 LDY #0 init octave # 3180 NW7 CMP #7 compare 0..7 3185 BCC NW8 in range? yes. 3190 SBC #7 subtract 7 3195 INY inc octave # 3200 JMP NW7 try again 3205 NW8 PHA save note # 3210 LDA OCTBL,Y octave offset 3215 STA NOTE save octave 3220 PLA get note # 3225 TAY use as index 3230 LDA NOTBL,Y note offset 3235 ADC NOTE add octave 3240 LDY ACCID accidental 3245 ADC ACTBL,Y accid offset 3250 STA NOTE save note 3255 LDA TRANSPOS,X transpose 3260 CMP #129 up/down point 3265 BCS TRANSDN down? 3270 ADC NOTE add note 3275 NW36 CMP #37 in range? 3280 BCC NW40 no. skip 3285 SBC #36 make in range 3290 JMP NW36 try again 3295 TRANSDN AND #$7F transpose 3300 STA TMP save it 3305 LDA NOTE get note 3310 SBC TMP transpose it 3315 NW37 CMP #37 in range? 3320 BCC NW40 yes. skip 3325 ADC #36-1 make in range 3330 JMP NW37 try again 3335 ; 3340 OCTBL .BYTE 0,12,24,36 octave table 3345 ACTBL .BYTE 0,$FF,1 accidental table 3350 NOTBL .BYTE 0,2,4,5 note table 3355 .BYTE 7,9,11 3360 ; 3365 NW40 TAY use as index 3370 LDA NOTES,Y get actual note 3375 STA VNOTE,X save it 3380 LDY XSTORE get index 3385 STA AUDF1,Y poke hardware 3390 ; 3395 ; Compute note duration. 3400 ; 3405 GETDURA INC PTRL,X pointer tbl lo 3410 BNE GDUR1 overflow? 3415 INC PTRH,X yes.pointer hi 3420 GDUR1 LDA PTRL,X pointer tbl lo 3425 STA PTR pointer lo 3430 LDA PTRH,X pointer tbl hi 3435 STA PTR+1 pointer hi 3440 LDY #0 get zero 3445 STY TIED,X zero tied flag 3450 LDA (PTR),Y duration byte 3455 ASL A minus => carry 3460 ROL TIED,X carry => 1=tied 3465 LSR A rotate back 3470 TAY use as index 3475 LDA GDTBL-1,Y actual duration 3480 STA DURCNT,X save it 3485 JMP INCX next voice 3490 ; 3495 GDTBL .BYTE 4,6,8 duration table 3500 .BYTE 12,16,24 3505 .BYTE 32,48,64 3510 .BYTE 96,128,192 3515 ; 3520 ; Erase text at screen bottom. 3525 ; 3530 ERASE LDX #39 40 bytes 0..39 3535 LDA #0 display blank 3540 ERSC STA TX1,X store in window 3545 DEX decrement index 3550 BPL ERSC done? 3555 RTS yes. continue 3560 ; 3565 ; If no data in memory. 3570 ; 3575 NODATA JSR ERASE erase window 3580 LDX #NTX&$FF no data msg lo 3585 LDY #NTX/256 no data msg hi 3590 JSR PRINTD print it 3595 JMP CHOICE goto menu 3600 ; 3605 ; Add VIBRATO. 3610 ; 3615 VIBRATO LDX #3 init index 3620 LDY #6 hardware index 3625 VBRT DEC VIBCNT,X v.speed count 3630 BNE VNXTX done? yes. 3635 LDA VSTAT,X vibrato status 3640 BEQ RAISE 0=raise pitch 3645 LDA VNOTE,X get frequency 3650 STA AUDF1,Y poke hardware 3655 DEC VSTAT,X vstat=0 3660 JMP PUTVIB continue 3665 RAISE LDA VNOTE,X get frequency 3670 BEQ VNXTX 0=no sound 3675 SEC set carry 3680 SBC VRANGE,X sub vib range 3685 STA AUDF1,Y poke hardware 3690 INC VSTAT,X vstat=1 3695 PUTVIB LDA VSPEED,X vibrato speed 3700 STA VIBCNT,X v.speed count 3705 VNXTX DEY hardware index 3710 DEY do it twice 3715 DEX dec index 3720 BPL VBRT done? no. 3725 RTS continue 3730 ; 3735 ; Print current sound value. 3740 ; 3745 CURRENT STA FR0 save value 3750 LDX #CTX&$FF current msg lo 3755 LDY #CTX/256 current msg hi 3760 CURNT2 JSR PRINTU print in top 3765 STA FR0+1 zero in F.P. hi 3770 JSR IFP INTEGER to F.P. 3775 JSR FASC F.P. to ASCII 3780 CLD clear decimal 3785 LDY #$FF init index 3790 PNUM INY inc index 3795 LDA (INBUFF),Y get ASCII 3800 AND #$1F to display code 3805 STA TX1+15,Y put msg window 3810 LDA (INBUFF),Y get ASCII 3815 BPL PNUM end of string 3820 RTS yes. continue 3825 ; 3830 ; Add delay to create TEMPO. 3835 ; 3840 DELAY LDA TEMPO music tempo 3845 STA TMP save it 3850 DEL LDA #4 do SYN 4 times 3855 STA TMP2 save count 3860 DEL1 LDY #48 delay loop cnt 3865 DEL2 DEY dec count 3870 BNE DEL2 done? no. 3875 JSR SYN synthesizer 3880 DEC TMP2 dec 4 times cnt 3885 BNE DEL1 done? no. 3890 JSR VIBRATO vibrato effect 3895 DEC TMP dec tempo value 3900 BNE DEL done? no. 3905 RTS continue 3910 ; 3915 ; Plug in default values. 3920 ; 3925 PDEFAULT JSR SHUTOFF zero sounds 3930 STA AUDCTL zero audio ctrl 3935 JSR SIOINV init hardware 3940 LDX #3 init index 3945 LDY #6 init tbl index 3950 DEF1 LDA #0 get zero 3955 STA TIED,X zero tied 3960 STA PTRL,X phrase tbl lo 3965 STA PTRH,X phrase tbl hi 3970 STA SYNSTAT,X syn status 3975 STA TRANSPOS,X transpose 3980 STA LINECNT,X voice line 3985 STA VCOUNT,X voice rpt cnt 3990 LDA #1 get one 3995 STA GETNOTE,X need new note 4000 STA STATUS,X need new record 4005 LDA #$AA define high vol 4010 STA HIGHVOL,X new high vol 4015 LDA #$A0 current volume 4020 STA VOLNOW,X new volnow 4025 LDA TABLE+21,Y voice tbl hi 4030 BNE DEF2 active? yes. 4035 STA STATUS,X shut off voice 4040 DEF2 DEX dec index 4045 DEY dec table index 4050 DEY do it twice 4055 BPL DEF1 done? no. 4060 RTS continue 4065 ; 4070 ; Check if all VOICEs are done. 4075 ; 4080 FINISHED LDA STATUS OR status 4085 ORA STATUS+1 of all voices 4090 ORA STATUS+2 together. if 4095 ORA STATUS+3 result <> 0, 4100 BNE ALLP keep playing 4105 LDA REPEAT play again? 4110 BEQ ALL3 no. end it 4115 DEC REPEAT dec repeat val 4120 JMP LISTEN play it again 4125 ALL3 JSR ERASE erase window 4130 JSR SHUTOFF stop all sound 4135 JMP CHOICE goto menu 4140 ALLP JMP PLAYING cont playing 4145 ; 4150 ; Stop all sound. 4155 ; 4160 SHUTOFF LDX #6 init index 4165 LDA #0 zero sound val 4170 SHUT STA AUDC1,X zero volume 4175 STA AUDF1,X zero frequency 4180 DEX dec index 4185 DEX do it again 4190 BPL SHUT done? no. 4195 RTS continue 4200 ; 4205 ; Check if the BREAK key 4210 ; has been pushed. 4215 ; 4220 BRKCHK LDA BRKKEY get break key 4225 BNE BRKX key hit? no. 4230 STOPIT DEC BRKKEY reset break 4235 JSR SHUTOFF turn off sound 4240 STA REPEAT reset repeat 4245 JSR ERASE erase window 4250 JMP CHOICE goto menu 4255 ; 4260 ; Set sound values to default. 4265 ; 4270 DEFAULT LDX #9 do ten phrases 4275 SYND LDA #64 default 4280 STA PDECAY,X decay 4285 STA PVSPEED,X vibrato speed 4290 LDA #1 default 4295 STA PATTACK,X attack 4300 LDA #0 default 4305 STA PVRANG,X vibrato range 4310 LDA #$A2 default 4315 STA PDROP,X minimum volume 4320 DEX dec index 4325 BPL SYND done? no. 4330 BRKX RTS continue 4335 ; 4340 ; Input and print a number. 4345 ; 4350 GETNUM LDA #0 get zero 4355 STA TMP save as pointer 4360 DEC TX2+15 cursor $FF 4365 GN1 JSR GETKEY get a letter 4370 CMP #RETURN is it a return 4375 BEQ GN3 yes. goto exit 4380 CMP #BACKS backspace? 4385 BNE GN2 no. goto GN2 4390 LDA TMP get pointer 4395 BEQ GN1 left margin=0? 4400 DEC TMP dec pointer 4405 LDX TMP use as index 4410 LDA #$FF cursor char 4415 STA TX2+15,X put cursor 4420 INC TX2+16,X make space 4425 JMP GN1 get a char 4430 GN2 LDX TMP get pointer 4435 CPX #3 three digits? 4440 BEQ GN1 yes. try again 4445 CMP #'0 .LT. ASCII 0? 4450 BCC GN1 yes. try again 4455 CMP #'9+1 .GT. ASCII 9? 4460 BCS GN1 yes. try again 4465 LDX TMP get index 4470 STA NMBUF,X put in buffer 4475 SBC #32-1 display code 4480 STA TX2+15,X put in window 4485 LDA #$FF cursor char 4490 STA TX2+16,X put cursor 4495 INC TMP inc position 4500 JMP GN1 get a char 4505 GN3 LDX TMP get pointer 4510 BNE GN4 any characters? 4515 INC TMP no. set <>zero 4520 RTS continue 4525 GN4 LDA #NMBUF&$FF buffer adr lo 4530 STA INBUFF inbuff pntr lo 4535 LDA #NMBUF/256 buffer adr hi 4540 STA INBUFF+1 inbuff pntr hi 4545 LDA #0 non numeric 4550 STA NMBUF,X number +1 4555 STA CIX FP offset 4560 JSR AFP ASCII to F.P. 4565 JSR FPI F.P. to INTEGER 4570 CLD clear decimal 4575 LDA FR0 get value 4580 LDX FR0+1 test >255 4585 BEQ GN5 no. ok. 4590 LDX #$80 set minus flag 4595 GN5 RTS continue 4600 ; 4605 ; Name the INPUT device. 4610 ; 4615 NAMEIT LDX #ITX&$FF device msg lo 4620 LDY #ITX/256 device msg hi 4625 JSR PRINTU print it 4630 STA TMP init index 4635 DEC TX2 init cursor $FF 4640 NMT1 JSR GETKEY get character 4645 LDX TMP get index 4650 CMP #BACKS backspace? 4655 BNE NMT2 no. on screen 4660 NMTD TXA yes. test index 4665 BEQ NMT1 left margin=0? 4670 DEC TMP position left 4675 LDA #$FF get cursor 4680 STA TX2-1,X put screen 4685 INC TX2,X turn off cursor 4690 JMP NMT1 try again 4695 NMT2 STA NAME,X ascii name buf 4700 CMP #RETURN return key? 4705 BEQ NMT5 yes. goto NMT5 4710 SEC set carry 4715 SBC #32 display code 4720 STA TX2,X put screen 4725 LDA #$FF get cursor 4730 STA TX2+1,X put screen 4735 INC TMP inc index sav 4740 INX inc index 4745 CPX #17 18 char yet? 4750 BNE NMT1 no. get more 4755 JMP NMTD delete last 4760 NMT5 INC TX2,X delete cursor 4765 RTS continue 4770 ; 4775 ; Controls operation of 4780 ; the SYNTHESIZER section, 4785 ; attack and decay. 4790 ; 4795 SYN LDX #3 init index 4800 LDY #6 hardware index 4805 SYN2 LDA SYNSTAT,X voice active? 4810 BEQ NXTX no. do another 4815 DEC SYNCNT,X syn dur count 4820 BNE NXTX count done? no. 4825 CMP #1 do attack? 4830 BEQ ATTCK yes. 4835 CMP #2 do decay? 4840 BEQ DECY yes. 4845 JMP NXTX next voice 4850 ATTCK INC VOLNOW,X inc volume 4855 LDA VOLNOW,X current volume 4860 STA AUDC1,Y poke hardware 4865 CMP HIGHVOL,X at maximum? 4870 BEQ GODECAY yes. now decay 4875 LDA ATTACK,X attack duration 4880 JMP DEC3 continue 4885 GODECAY INC SYNSTAT,X make decay 4890 DEC2 LDA DECAY,X decay duration 4895 DEC3 STA SYNCNT,X syn dur count 4900 JMP NXTX next voice 4905 DECY LDA VOLNOW,X current volume 4910 CMP DROP,X compare low vol 4915 BEQ GOSUSTN =low volume? 4920 BCC GOSUSTN